package cn.gcBlock.utils;
import org.apache.commons.codec.binary.Base64;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class BlockEncryptUtils {

    private static Signature signature;

    static {
        try {
            signature = Signature.getInstance("SHA256withECDSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    //生成公私钥
    public static Map<String,String> generateKeyPair() {
        KeyPair keyPair = null;
        try {
            ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256k1");
            KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("EC");
            keyGenerator.initialize(ecGenParameterSpec, new SecureRandom());
            keyPair = keyGenerator.generateKeyPair();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Map<String,String> map = new HashMap();
        byte[] bytes = keyPair.getPrivate().getEncoded();
        String privateKey = Base64.encodeBase64String(bytes);
        String publicKey = Base64.encodeBase64String(keyPair.getPublic().getEncoded());
        map.put("privateKey",privateKey);
        map.put("publicKey",publicKey);
        return map;
    }

    public static <T> T loadKey(String encodedKeyString, String algorithm, String type)
            throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
        byte[] encodedKey =  Base64.decodeBase64(encodedKeyString);
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        if (type.equals("static")) {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            return (T) publicKey;
        } else if (type.equals("private")) {
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            return (T) privateKey;
        } else {
            return null;
        }

    }

    //签名
    public static String sign(String dataJsonString, String privateKeyString) throws GeneralSecurityException, IOException {
        PrivateKey privateKey = loadKey(privateKeyString, "EC", "private");
        byte[] data = Base64.decodeBase64(dataJsonString);
        signature.initSign(privateKey);
        signature.update(data);
        byte[] encodedKey = signature.sign();
        String result = Base64.encodeBase64String(encodedKey);
        return result;
    }

    //验证
    public static boolean verify(String dataJsonString, String signatureString, String publicKeyString) {
        try{
        PublicKey publicKey = loadKey(publicKeyString, "EC", "static");
        byte[] data =  Base64.decodeBase64(dataJsonString);
        byte[] signData =  Base64.decodeBase64(signatureString);
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(signData);
        }catch (Exception e){
            e.printStackTrace();
            return  false;
        }
    }

    public static String toSerializable(Object o) {
        String result = null;
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream);
            outputStream.writeObject(o);
            byte[] bytes = byteArrayOutputStream.toByteArray();
            result = Base64.encodeBase64String(bytes);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void main(String[] args) throws GeneralSecurityException, IOException {
        //生成公私钥
        String publicKeyString = "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEj8SfNPh1eGzX1USt/Oac/5So3GXwMAMwrgJuiAUDecSQ+OZOg5Un0jn2HvlrSQA6HP/Z8OEfYgZhjIUAvBo9jQ==";
        String privateKeyString = "MD4CAQAwEAYHKoZIzj0CAQYFK4EEAAoEJzAlAgEBBCAtzc46vTLPcXUM+Tc7OegdxkRXnze8dwUP5H9LnDRvSg==";
        //签名的数据
        String signDataString = sign("数据1", privateKeyString);
        //参数1实体数据 参数2 签名的数据， 参数3 公钥 === 验证
        boolean boo = verify("数据1", signDataString, publicKeyString);
        System.out.println(boo);
    }
}
